"""
使用分布式进程实现分布式任务处理。

知识点：
    1.在Thread和Process中，应当优选Process，因为Process更稳定，而且Process可以分布到多台机器上，而Thread最多只能分布到同一台机器的多个CPU上。
    2.Python的multiprocessing模块不但支持多进程，其中managers子模块还支持把多进程分布到多台机器上。
      一个服务进程可以作为调度者，将任务分布到其他多个进程中，依靠网络通信。

特别提示：
    注意Queue的作用是用来传递任务和接收结果，每个任务的描述数据量要尽量小。
    比如发送一个处理日志文件的任务，就不要发送几百兆的日志文件本身，而是发送日志文件存放的完整路径，由Worker进程再去共享的磁盘上读取文件。
"""

from random import randint
from queue import Queue
from multiprocessing.managers import BaseManager

# 发送任务的队列
task_queue = Queue()

# 接收结果的队列
result_queue = Queue()


class QueueManager(BaseManager):
    """
    队列管理
    """
    pass


# 将队列注册到网络上
QueueManager.register("get_task_queue", callable=lambda: task_queue)
QueueManager.register("get_result_queue", callable=lambda: result_queue)


def put_task(task_q):
    """
    放入任务
    """

    for i in range(100):
        n = randint(0, 10000)
        print("放入任务 {task_obj}".format(task_obj=n))
        task_q.put(n)


def get_result(result_q):
    """
    从result队列读取结果
    """

    print("尝试获取任务结果")
    for i in range(100):
        r = result_q.get(timeout=10)
        print("任务结果为：{result_obj}".format(result_obj=r))


def run():
    # 绑定端口和设置验证码
    manager = QueueManager(address=('127.0.0.1', 8000), authkey=b"Admin123$")
    manager.start()

    # 获得网络访问的Queue对象
    task_q = manager.get_task_queue()
    result_q = manager.get_result_queue()

    # 放入任务
    put_task(task_q)

    # 从result队列读取结果
    get_result(result_q)

    # 关闭
    manager.shutdown()
    print("Master退出")


if __name__ == "__main__":
    run()
